#include <iostream>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/keyvalq_struct.h>
#include <event2/buffer.h>
#ifndef _WIN32
#include <signal.h>
#endif
#include <string.h>
#include <string>
using namespace std;

#define WEBROOT "."
#define DEFAULT_INDEX "index.html"

void  http_cb(struct evhttp_request *request, void *){
        cout<<"http_cb"<<endl;
        // 获取浏览器的请求信息
        //uri
        const char *uri = evhttp_request_get_uri(request);
        cout<<"uri = "<<uri<<endl;

        //请求类型 GET POST
        string method;
        switch(evhttp_request_get_command(request)){
                case EVHTTP_REQ_GET:
                        method = "GET";
                        break;
                case EVHTTP_REQ_POST:
                        method = "POST";
                        break;
                default:
                        break;
        }
        cout<<"method = "<< method<<endl;

        //消息报头
        evkeyvalq *headers = evhttp_request_get_input_headers(request);
        cout<<"======headers======"<<endl;
        for (evkeyval *p = headers->tqh_first; p != NULL;  p = p->next.tqe_next){
                cout<<p->key<<":"<<p->value<<endl;
        }
        
        //请求正文(GET不一定有 POST有表单信息) 
        evbuffer *inbuf = evhttp_request_get_input_buffer(request);
        char buf[1024] = {0};
        cout<<"======input data======"<<endl;
        while (evbuffer_get_length(inbuf)){
                int n = evbuffer_remove(inbuf, buf , sizeof(buf)-1);
                if(n > 0){
                        buf[n] = '\n';
                        cout<<buf<<endl;
                }
        }
        

        //回复浏览器
        //状态行 消息报头 响应正文
        
        // 分析出请求的文件 uri
        // 设置根目录 WEBROOT
        string filepath = WEBROOT;
        filepath += uri;
        if(strcmp(uri, "/") == 0){
                //默认加上首页文件
                filepath += DEFAULT_INDEX;
        }

        //消息报头
        evkeyvalq *outhead = evhttp_request_get_output_headers(request);
        //要支持图片 js css 下载zip文件
        //获取文件的后缀名
        ///root/index.html
        int pos = filepath.rfind('.');
        string suffix =   filepath.substr(pos+1, filepath.size()-(pos+1));
        if(suffix == "jpg" || suffix=="gif" || suffix == "png"){
                string tmp = "image/"+suffix;
                evhttp_add_header(outhead, "Content-Type", tmp.c_str());
        }else if(suffix == "zip"){
                evhttp_add_header(outhead, "Content-Type", "application/zip");
        }else if(suffix == "html"){
                evhttp_add_header(outhead, "Content-Type", "text/html;charset=UTF8");
                //evhttp_add_header(outhead, "Content-Type", "text/html");
        }else if(suffix == "css"){
                 evhttp_add_header(outhead, "Content-Type", "text/css");
        }else if(suffix == "js"){
                 evhttp_add_header(outhead, "Content-Type", "text/js");
        }

        FILE *fp = fopen(filepath.c_str(), "rb");
        if(!fp){
                evhttp_send_reply(request, HTTP_NOTFOUND, "",  NULL );
                return ;
        }

        evbuffer *outbuf = evhttp_request_get_output_buffer(request);
        for ( ; ;){
                int len = fread(buf, 1, sizeof(buf), fp);
                if(len<=0)break; 
                evbuffer_add(outbuf, buf, len);
        }

        fclose(fp);
        evhttp_send_reply(request, HTTP_OK, "", outbuf );
        return ;        
}

int main(int argc, char const *argv[]){
#ifdef _WIN32
        //初始化socket库
        WSADATA wsa;
        WSAStartup(MAKEWORD(2,2), &wsa);
#else
        //忽略管道信号 发送数据给已关闭的socket
        if(signal(SIGPIPE,SIG_IGN) == SIG_IGN){
                return 1;
        }
#endif  

        event_base *base = event_base_new();

        //http服务器
        //1.创建evhttp上下文
        evhttp *evh = evhttp_new(base);

        //2.绑定端口和ip
        int ret = evhttp_bind_socket(evh, "0.0.0.0", 8080);
        if(ret != 0){
                cerr<<"evhttp_bind_socket failed!"<<endl;
        }

        //3. 设定回调函数
        evhttp_set_gencb(evh,  http_cb, NULL);

        event_base_dispatch(base);

        evhttp_free(evh);

        event_base_free(base);

        return 0;
}
 